
/**
 * 按键绑定对象
 *
 * @class keyEvent
 */
class keyEvent {

    constructor() {
        /**
         * 按键绑定对象配置参数
         * @memberof keyEvent
         */
        this.config = {
            /**
             * 是否阻断默认事件
             * @memberof keyEvent
             */
            prevent: true,
        };
        /**
         * 事件缓存对象
         * @memberof keyEvent
         */
        this.events = {};
        /**
         * 键盘绑定事件对应键值
         * @memberof keyEvent
         */
        this.keyMap = {
            65: 'a', 74: 'j', 83: 's', 49: '1',
            66: 'b', 75: 'k', 84: 't', 50: '2',
            67: 'c', 76: 'l', 85: 'u', 51: '3',
            68: 'd', 77: 'm', 86: 'v', 52: '4',
            69: 'e', 78: 'n', 87: 'w', 53: '5',
            70: 'f', 79: 'o', 88: 'x', 54: '6',
            71: 'g', 80: 'p', 89: 'y', 55: '7',
            72: 'h', 81: 'q', 90: 'z', 56: '8',
            73: 'i', 82: 'r', 48: '0', 57: '9',
            37: 'left', 38: 'up', 39: 'right', 40: 'down',
            96: 'num0', 104: 'num8', 112: 'f1', 118: 'f7',
            97: 'num1', 105: 'num9', 113: 'f2', 119: 'f8',
            98: 'num2', 106: 'num*', 114: 'f3', 120: 'f9',
            99: 'num3', 107: 'num+', 115: 'f4', 121: 'f10',
            100: 'num4', 108: 'numenter', 116: 'f5', 122: 'f11',
            101: 'num5', 109: 'num-', 117: 'f6', 123: 'f12',
            102: 'num6', 110: '.',
            103: 'num7', 111: '/',
            8: 'backspace', 27: 'esc',
            9: 'tab', 32: 'spacebar',
            12: 'clear', 33: 'pageup',
            13: 'enter', 34: 'pagedown',
            16: 'shift', 35: 'end',
            17: 'control', 36: 'home',
            18: 'alt', 20: 'capelock',
            45: 'insert',
            46: 'delete',
            144: 'numlock',
            189: '-',
            190: '.',
            191: '/',
            192: '`',
            219: '[',
            186: ';',
            187: '=',
            188: ',',
            220: '\\',
            222: '\'',
            221: ']',
        };
        /**
         * 已经按下的按键缓存对象
         * @memberof keyEvent
         */
        this.keyDownString = {};
        window.onkeydown = event => {
            var EventString = this.keyEventToString(event);
            if (!this.keyDownString[EventString] && this.events[EventString] && this.events[EventString].keyDown) {
                this.events[EventString].keyDown.map(i => i());
            }
            this.keyDownString[EventString] = true;
            return this.config;
        };
        window.onkeyup = event => {
            var EventString = this.keyEventToString(event);
            delete this.keyDownString[EventString];
            if (!this.keyDownString[EventString] && this.events[EventString] && this.events[EventString].keyUp) {
                this.events[EventString].keyUp.map(i => i());
            }
            return this.config;
        };
    };

    /**
     * 判断按键是否被按下
     *
     * @param {Array} keyArray 需要检测的按键数据
     * @return {Blob} 按键是否按下
     * @memberof keyEvent
     */
    getKeyPerss(keyArray) {
        var isKeyPerss = false;
        for (const key in this.keyDownString) {
            const element = this.keyDownString[key];
            if (element && keyArray.includes(key)) {
                isKeyPerss = true;
                break;
            }
        }
        return isKeyPerss;
    }

    /**
     * 将按下的按键转换为绑定事件的按键字符串
     *
     * @param {Event} event window按键对象
     * @return {*} 
     * @memberof keyEvent
     */
    keyEventToString(event) {
        var EventString = [];
        if (event.ctrlKey) EventString.push('ctrl');
        if (event.altKey) EventString.push('alt');
        if (event.shiftKey) EventString.push('shift');
        EventString.push(this.keyMap[event.keyCode]);
        return EventString.join('+');
    }


    /**
     * 将绑定用的键盘按键转化为对应的键盘绑定事件 key值
     *
     * @param {String} keyString 键盘绑定事件的按键键代码
     * @return {String} 转换为对应的按键对象
     * @memberof keyEvent
     */
    formatKeyString(keyString) {
        var _keyString = keyString.toLocaleLowerCase();
        var EventString = [];
        var keyArray = ['_', '>', '?', '~', '{', ':', 'add', '<', '|', '"', '}'];
        var _keyArray = ['-', '.', '/', '`', '[', ';', '=', ',', '\\', '\'', ']',];
        var _$keyString = _keyString;
        keyArray.map((item, index) => {
            if (_keyString.indexOf(item) != -1) {
                _$keyString = _keyString.replace(item, 'shift+' + _keyArray[index]);
            }
        });
        _keyString = _$keyString;
        if (_keyString.indexOf('ctrl') != -1) {
            EventString.push('ctrl');
            _keyString = _keyString.replace('ctrl', '');
        }
        if (_keyString.indexOf('alt') != -1) {
            EventString.push('alt');
            _keyString = _keyString.replace('alt', '');
        }
        if (_keyString.indexOf('shift') != -1) {
            EventString.push('shift');
            _keyString = _keyString.replace('shift', '');
        }
        _keyString = _keyString.replaceAll('+', '');
        EventString.push(_keyString);
        return EventString.join('+');
    }

    /**
     * 键盘按键事件绑定
     *
     * @param {String} keyString 需要绑定的按键
     * @param {Function} downEvent 按下事件
     * @param {Function} upEvent 抬起事件
     * @memberof keyEvent
     */
    on(keyString, downEvent, upEvent) {
        var _keyString = this.formatKeyString(keyString);
        if (!this.events[_keyString]) this.events[_keyString] = {
            keyDown: [],
            keyUp: [],
        }
        if (downEvent) this.events[_keyString].keyDown.push(downEvent);
        if (upEvent) this.events[_keyString].keyUp.push(upEvent);
    }
    /**
     * 解除按键绑定
     *
     * @param {String} keyString 需要绑定的按键
     * @param {Function} downEvent 按下事件
     * @param {Function} upEvent 抬起事件
     * @memberof keyEvent
     */
    off(keyString, downEvent, upEvent) {
        var _keyString = this.formatKeyString(keyString);
        if (upEvent) {
            for (let i = 0; i < this.events[_keyString].keyUp.length; i++) {
                const item = this.events[_keyString].keyUp[i];
                if (item === upEvent) this.events[_keyString].keyUp.splice(i, 1);
                break;
            }
        }
        if (downEvent) {
            for (let i = 0; i < this.events[_keyString].keyDown.length; i++) {
                const item = this.events[_keyString].keyDown[i];
                if (item === downEvent) this.events[_keyString].keyDown.splice(i, 1);
                break;
            }
        }
        if (!downEvent && !upEvent) {
            delete this.events[_keyString];
        }
    }
}

var _keyEvent = new keyEvent();

export default _keyEvent;

